<?php
/*
Copyright (C) 2009 de Flotte Maxence

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
?>
<?php
/**
 * Gestion des entrés/sorties
 * Récupère et stoque des données sur la base de données
 */
 
class ZzIO {
	
	public $domain;
	public $readable = false;
	public $writable = false;
	private $tableName;
	public $_needs = array();
	private $_allneeds = array();
	private $_responces = array();
	public $id;
	private $domainName;
	private $_labelDomTypes = array();
	private $queryWasExecuted = false;
	private $tr;
	private $trDom;
	private $nbChildsPerPage = 10;
	private $previewButton = false;
	private $childsOrder = 'ASC';
	private $childsOrderBy = 'dateC';
	private $createChilds = array();
	private $_autocreateChildsPermissions = null;
	private $_parentsToAdd = array();
	private $_parentsToUnlink = array();
	private $_criteriaForChildren = array();
	public $externalQuery = null; //Objet externe permettant de lier les requêtes de tout les enfants
	private $redirection = 'this';
	private $addForm = '';
	//public static $_instances = array();
	
	
	/**
	 * Get an instance of a class ZzIO (singleton)
	 * @param int $id id of the label
	 * @return ZzIO
	 */
	public static function getInstance($id = null) {
		if(!isSet($GLOBALS['ioInstance'][(is_null($id))?0:$id])) {
			$GLOBALS['ioInstance'][(is_null($id))?0:$id] = new ZzIO($id);
		}
		return $GLOBALS['ioInstance'][(is_null($id))?0:$id];
	}

	/**
	 * Get an instance of a class ZzIO but with a new array _need
	 * @param int $id id of the label
	 * @return ZzIO
	 */
	public static function getCleanedInstance($id = null) {
		if(!isSet($GLOBALS['ioInstance'][(is_null($id))?0:$id])) {
			$GLOBALS['ioInstance'][(is_null($id))?0:$id] = new ZzIO($id);
		}
		else {
			$GLOBALS['ioInstance'][(is_null($id))?0:$id]->_need = array();
		}
		return $GLOBALS['ioInstance'][(is_null($id))?0:$id];
	}
	
	public function __construct($id = null) {
		
		//le dictionnaire
		$this->tr = new ZzTranslation('dom_errors');
		$this->trDom = new ZzTranslation('dom_labels');
		//Si $id non null alors, on doit récupérer les info depuis la base de donnée
		if(!empty($id) and is_numeric($id)) {
			$this->id = $id;

			if($GLOBALS['store'] and file_exists('./ZzStore/'.$this->id.'.php')) {
					$_res = unserialize(file_get_contents('./ZzStore/'.$this->id.'.php'));
					$name = $_res['name'];
					$dateC = $_res['dateC'];
					$dateU = $_res['dateU'];
					$user = $_res['user'];
					$group = $_res['group'];
					//$chmod = $_res['userR'].','.$_res['userW'].','.$_res['groupR'].','.$_res['groupW'].','.$_res['otherR'].','.$_res['otherW'];
					$userR = $_res['userR'];
					$userW = $_res['userR'];
					$groupR = $_res['groupR'];
					$groupW = $_res['groupW'];
					$otherR = $_res['otherR'];
					$otherW = $_res['otherW'];
					$type = $_res['type'];
			}
			else {
				$_res = ZzSQL::queryFirst('SELECT name, dateC, dateU, user, `group`, type, userR, userW, groupR, groupW, otherR, otherW FROM '.$GLOBALS['prefix'].'label WHERE id = ?',array($this->id));
				if($_res != null) {
					$name = $_res['name'];
					$dateC = $_res['dateC'];
					$dateU = $_res['dateU'];
					$user = $_res['user'];
					$group = $_res['group'];
					//$chmod = $_res['userR'].','.$_res['userW'].','.$_res['groupR'].','.$_res['groupW'].','.$_res['otherR'].','.$_res['otherW'];
					$userR = $_res['userR'];
					$userW = $_res['userR'];
					$groupR = $_res['groupR'];
					$groupW = $_res['groupW'];
					$otherR = $_res['otherR'];
					$otherW = $_res['otherW'];
					$type = $_res['type'];
					
					if($GLOBALS['store'])
						file_put_contents('./ZzStore/'.$this->id.'.php',serialize($_res));
				}
			}
				
			//Si on a pas le droit en lecture
				if(!isReadable($user,$group,$_res['userR'],$_res['groupR'],$_res['otherR']) and !isReadable($user,$group,$_res['userW'],$_res['groupW'],$_res['otherW']))
					return false;
				$this->readable = isReadable($user,$group,$_res['userR'],$_res['groupR'],$_res['otherR']);
				$this->writable = isReadable($user,$group,$_res['userW'],$_res['groupW'],$_res['otherW']);

			//On récupère les labels parents
				$parentLabel = array();
		}
		//Si un identifiant est inconnu alors c'est un nouvel enregistrement
		elseif(empty($GLOBALS['label_id'])) {
			//C'est un enrgistrement nouvellement créé
			if(!empty($_SESSION['tmpId'.$GLOBALS['tmpId']]))
				$this->id = $_SESSION['tmpId'.$GLOBALS['tmpId']];
			//C'est un nouvel enregistrement
			else 
				$this->id = null;
				
			$name = '';
			$dateC = time();
			$dateU = time();
			$user = empty($_SESSION['user'])?1:$_SESSION['user'];
			$group = empty($_SESSION['group'][0])?1:$_SESSION['group'][0];
			$type = $GLOBALS['label_type'];
			$userR = 1;
			$userW = 1;
			$groupR = 1;
			$groupW = 0;
			$otherR = 1;
			$otherW = 0;
			//$chmod = '1,1,1,0,1,0';
			$parentLabel = ZzLabel::getParentId('last');
		}
		//C'est un enregistrement existant
		else {
			$this->id = @$GLOBALS['label_id'];
			$name = @$GLOBALS['label_name'];
			$dateC = @$GLOBALS['label_dateC'];
			$dateU = @$GLOBALS['label_dateU'];
			$user = @$GLOBALS['label_user'];
			$group = @$GLOBALS['label_group'];
			$type = @$GLOBALS['label_type'];
			//$chmod = @$GLOBALS["label_userR"].','.@$GLOBALS["label_userW"].','.@$GLOBALS["label_groupR"].','.@$GLOBALS["label_groupW"].','.@$GLOBALS["label_otherR"].','.@$GLOBALS["label_otherW"];
			$userR = $_res['label_userR'];
			$userW = $_res['label_userR'];
			$groupR = $_res['label_groupR'];
			$groupW = $_res['label_groupW'];
			$otherR = $_res['label_otherR'];
			$otherW = $_res['label_otherW'];
			//On récupère les labels parents
				$parentLabel = array();
		}
		
		
		$this->domainName = 'Dom'.$type;
		$this->tableName = $GLOBALS['prefix'].strToLower($type);
		$this->domain = new $this->domainName();
		
		//Si le domaine hérite d'un label
		if(is_subclass_of($this->domain, 'domlabel')) {
			$this->domain->id->setValue($this->id);
			$this->domain->name->setValue($name);
			$this->domain->dateC->setValue($dateC);
			$this->domain->dateU->setValue($dateU);
			$this->domain->user->setValue($user);
			$this->domain->group->setValue($group);
			$this->domain->type->setValue($type);
			$this->domain->parentLabel->value = $parentLabel;
			$this->domain->userR->setValue($userR);
			$this->domain->userW->setValue($userW);
			$this->domain->groupR->setValue($groupR);
			$this->domain->groupW->setValue($groupW);
			$this->domain->otherR->setValue($otherR);
			$this->domain->otherW->setValue($otherW);
			
			//$this->domain->chmod->setValue($chmod);
		}
		
			//Add lid reference
				if(!empty($this->id) and $GLOBALS['isStatic']) {
					$lid = intval(ZzLabel::getId());
					if($lid != $this->id) {
						$refFile = './ZzStore/ref'.$this->id.'.php';
						if(file_exists($refFile))
							$_ref = unserialize(file_get_contents($refFile));
						else
							$_ref = array();
						if(!in_array($_GET['label'],$_ref)) {
							$_ref[] = $lid;
							file_put_contents($refFile, serialize($_ref));
						}
					}
				}
	}
	
	public function noRedirection() {
		$this->redirection = '';
	}
	public function redirect2parent() {
		$this->redirection = 'parent';
	}
	public function redirect2Me() { //Default
		$this->redirection = 'this';
	}

	/**
	 * Definie les champs nécéssaires. Cet élément est optionnel pour la lecture, mais vital pour l'écriture
	 */
	public function need($arg,$arg2 = null) {
		if(is_null($this->externalQuery)) {
			if($arg2 == null) {
				if(!in_array($arg,$this->_needs)) {
					$this->_needs[] = $arg;
					if(!in_array($arg,$this->_allneeds)) {
						$this->_allneeds[] = $arg;
						$this->queryWasExecuted = false;
					}
				}
			}
			else {
				if(!in_array(array($arg,$arg2),$this->_needs)) {
					$this->_needs[] = array($arg,$arg2);
					if(!in_array(array($arg,$arg2),$this->_allneeds)) {
						$this->_allneeds[] = array($arg,$arg2);
						$this->queryWasExecuted = false;
					}
				}
			}
		}
		else
			$this->externalQuery->need($arg,$arg2);
	}
		
	/**
	 * Definie les champs qui ne sont plus nécéssaires.
	 */
	public function dontNeed($arg) {
		if(in_array($arg,$this->_needs)) {
			$key = array_search($arg, $this->_needs);
			unSet($this->_needs[$key]);
		}
	}
	
	/**
	 * Effectue la requête SQL dans le but de collecter les données
	 * @return bool return true en cas de réussite, false dans le cas contraire
	 */
	private function execQuery() {
		//Si la requête passe par un objet externe (cas des children)
		if(!is_null($this->externalQuery)) {
			$this->_responces = $this->externalQuery->execQuery($this->id);
			return;
		}
		// Si la requête a déjà été executée
		if($this->queryWasExecuted)
			return;
		$this->queryWasExecuted = true;

		$nbArgs = 0;
		$_tables = array(); //Liste des tables
		$query = 'SELECT ';
		$resp = 2;
		$first = true;
		foreach($this->_needs as $value) {
			//if(!in_array($val,array('name','dateC','dateU','user','group','type','id'))) {
				if($first)
					$first = false;
				else
					$query .= ', ';
				if(is_array($value))
					$query .= '`'.$GLOBALS['prefix'].strToLower($value[0]).'`.`'.$value[1].'` ';
				else
					$query .= '`'.$GLOBALS['prefix'].strToLower($this->domain->$value->dom).'`.`'.$value.'` ';

				$nbArgs++;
				
				if(is_array($value)) {
					if(!in_array(array($this->domain->$value[0]->dom,$value[0],$value[0]),$_tables))
						$_tables[] = array($this->domain->$value[0]->dom,$value[0],$value[0]);
				}
				elseif($this->domain->$value->dom != 'label') {
					if(!in_array(array('label',$this->domain->$value->dom,'id'),$_tables))
						$_tables[] = array('label',$this->domain->$value->dom,'id');
				}
		}
		
		//Liste des tables
		$listTable = '';
		for($i = 0; $i<count($_tables);$i++) {
			$listTable .= ' INNER JOIN `'.$GLOBALS['prefix'].strToLower($_tables[$i][1]).'` ON `'.$GLOBALS['prefix'].strToLower($_tables[$i][1]).'`.id = `'.$GLOBALS['prefix'].strToLower($_tables[$i][0]).'`.'.$_tables[$i][2].'';
		}
		$query .= 'FROM `'.$GLOBALS['prefix'].'label`'.$listTable.' WHERE `'.$GLOBALS['prefix'].'label`.id = ?';

		if($this->id != null)  {
			if($nbArgs > 0) {
				$_data = ZzSQL::queryFirst($query,array($this->id));

				foreach($this->_needs as $val) {
					if(!is_array($val)) {
					//Enregistrement des variables POST
					if(isSet($_POST[$val]))
						$this->domain->$val->setValue($_POST[$val]);
					elseif(isSet($_data[$val]))
						$this->domain->$val->setValue($_data[$val]);
					
					$this->_responces[$val] = $this->domain->$val->value;
					//On ajoute les value aux entités
					
					//else
					//	$this->_labelDomTypes[$val]->setValue($this->_responces[$val]);
					}
					else {
						$this->_responces[$val[1]] = $_data[$val[1]];
					}
				}
			}
		}
		else {
			foreach($this->_needs as $val) {
				if(isSet($_POST[$val]))
					$this->_responces[$val] = $_POST[$val];
				else
					$this->_responces[$val] = '';
			}
		}
	}
	
	/**
	 * Recupère un champs domType
	 * @return DomType
	 */
	public function get($val,$val2 = null) {
		
		if(is_null($val2)) {
			$this->need($val);
			$this->execQuery();
			$this->domain->$val->setValue(@$this->_responces[$val]);
			return $this->domain->$val;
		}
		else {
			$this->need(array($val,$val2));
			$this->execQuery();
			return @$this->_responces[$val2];
		}

	}
	
	/**
	 * Ajouter du code html dans le form
	 */
	public function add2Form($html) {
		$this->addForm .= $html;
	}
	
	/**
	 * Recuperer le formulaire
	 * @return string
	 */
	public function getForm() {
		$this->isNotCommitable(); 
		
		$form = '<form method="post" id="IOForm'.$this->id.'" class="IOForm'.$this->domainName.' IOForm">
	<input type="hidden" value="'.$GLOBALS['tmpId'].'" name="tmpId"/>
'.$this->addForm;
		foreach($this->_needs as $key) {
			if(!isset($this->_responces[$key]))
				$this->execQuery();
				
			//On récupère les erreurs éventuels
				if(!empty($GLOBALS['errors'][$key])) {
					$formError = '<span class="error">'.$GLOBALS['errors'][$key].'</span>';
					$class = 'IOFormEltWithError';
				}
				else {
					$formError = '';
					$class = 'IOFormElt';
				}
				
			/*if(in_array($key,array('name','dateC','dateU','user','group','type','id'))) {
				$this->_labelDomTypes[$key]->setValue(@$this->_responces[$key]);
				
				$form .= '	<div class="'.$class.'">';
				$form .= $this->_labelDomTypes[$key]->in().$formError.'</div>
';
			}
			else {*/
				$this->domain->$key->setValue(@$this->_responces[$key]);
				$form .= '	<div class="IOFormElt">';
				$form .= $this->domain->$key->in().$formError.'</div>
';
			//}
			
		}
		
		//Bouton d'aperçu ?
		$button = '';
		if($this->previewButton)
			$button = '<input type="submit" name="IOFormView'.$this->id.'" value="aperçu"/>';
	
		$form .= '
	<div class="IOFormSubmit">
		<input type="submit" name="IOForm'.$this->id.'"/>'.$button.'
	</div>
</form>
';
		return $form;
	}
	
	/**
	 * Affiche le boutton d'apperçu dans le formulaire
	 */
	public function enablePreviewButton() {
		$this->previewButton = true;
	}
	
	/**
	 * informe si clic sur aperçu
	 */
	public function isPreview() {
		if(isSet($_POST['IOFormView'.$this->id]))
			return true;
		return false;
	}
	
	/**
	 * récupérer les informations du label
	 * @return string
	 */
	public function getValue() {
		$div = '<div id="IOForm'.$this->id.' IOForm'.$this->domainName.'">
';
		foreach($this->_needs as $key) {
			if(!isset($this->_responces[$key]))
				$this->execQuery();
			/*if(in_array($key,array('name','dateC','dateU','user','group','type','id'))) {
				$this->_labelDomTypes[$key]->setValue(@$this->_responces[$key]);
				$div .= $this->_labelDomTypes[$key]->out().'<br />
';
			}*/
			//else {
				$this->domain->$key->setValue($this->_responces[$key]);
				$div .= $this->domain->$key->out().'<br />
';
			//}
		}
		$div .= '</div>
';
		return $div;
	}
		
	/**
	 * Renseigne les champs d'une ref d'un user
	 * @param string $ref référence
	 * @param string $value valeur de la nouvelle ref
	 * @param int $user identifiant du user
	 * @return void
	 */
	public function setUserRef($ref,$value,$user = null) {
		if(is_null($user) and isset($_SESSION['user']))
			$user = $_SESSION['user'];
		$query = 'UPDATE `'.$GLOBALS['prefix'].$this->domain->$ref->dom.'_'.$this->domain->$ref->ref.'` SET `'.$ref.'` = \''.$value.'\' WHERE id=? AND user=?';
		
		if(ZzSQL::exec($query,array($this->id,$user)) == 0) { //If it's not Ok, we have to CREATE the ref
			$query = 'INSERT INTO `'.$GLOBALS['prefix'].$this->domain->$ref->dom.'_'.$this->domain->$ref->ref.'`(id,user,`'.$ref.'`) VALUES(?,?,?)';
			ZzSQL::exec($query,array($this->id,$user,$value));
		}
	}
	
	/**
	 * Update des champs d'une ref
	 * @param string $ref référence
	 * @param string $value valeur de la nouvelle ref
	 * @return void
	 */
	public function setRef($ref,$value) {
		$query = 'UPDATE `'.$GLOBALS['prefix'].$this->domain->$ref->dom.'_'.$this->domain->$ref->ref.'` SET `'.$ref.'` = \''.$value.'\' WHERE id=?';
		ZzSQL::exec($query,array($this->id));
	}
	/**
	 * Définition de critère de sélection pour les enfants
	 * @param string $ref champs à filtrer
	 * @param string $operator 'motif' de la comparaison (<, >, <=, >=, =, <>)
	 * @param string $value valeur de comparaison
	 * @return void
	 */
	public function defCriteria($ref,$operator,$value) {
		$this->_criteriaForChildren[$ref] = array('operator' => $operator, 'value' => $value);
	}
	
	/**
	 * récupérer les enfant du label
	 * @return array
	 */
	public function getAllChildren($type = null) {
		return $this->getChildren($type,true);
	}
	/**
	 * récupérer les enfant du label
	 * @return array
	 */
	public function getChildren($type = null,$noLimit=false) {
		$_childs = array(); //liste des enfants
		
		//Numéro de la page
			$page = 0;
			if(!empty($_GET['page']) > 0)
				$page = intval($_GET['page']);
				
			//Variable des inner join pour les domref
				$innerJoinL = '';
				$innerJoinR = '';
					
		//Construction du critère de limitation des droit
			//Si statique, seul les enfants avec droit en lectures pour tous
			if($GLOBALS['isStatic'])
				$rightCriteria = ' AND otherR = 1';
			//Si dynamique 
			else {
				if(!empty($_SESSION['group']))
					foreach($_SESSION['group'] AS $key => $grp)
						if($key == 0)
							$listGroup = $grp;
						else
							$listGroup .= '|'.$grp;
				else
					$listGroup = '0';
				if(!empty($_SESSION['user']))
					$user = $_SESSION['user'];
				else
					$user = '0';
				$rightCriteria = ' AND ((OtherR=1) OR (GroupR = 1 AND `'.$GLOBALS['prefix'].'label`.`Group` REGEXP \'^'.$listGroup.'$\') OR (UserR = 1 AND `'.$GLOBALS['prefix'].'label`.User = '.$user.'))';
				
				//Critère de sélection (domRef)
				if(!is_null($type)) {
					//On récupère le domaine
					$domainName = 'Dom'.$type;
					$domain = new $domainName();
					
					foreach($this->_criteriaForChildren as $key => $val) {

						$rightCriteria .= ' AND `'.$GLOBALS['prefix'].$domain->$key->dom.'_'.$domain->$key->ref.'`.`'.$key.'` '.$val['operator'].' '.$val['value'];
						if($domain->$key->ref == 'user')
							$rightCriteria .= ' AND `'.$GLOBALS['prefix'].$domain->$key->dom.'_'.$domain->$key->ref.'`.`user` = '.$_SESSION['user'];
						elseif($domain->$key->ref == 'group')
							;
							/**
							* @TODO
							**/

							$innerJoinL .= '(';
							$innerJoinR .= ') INNER JOIN `'.$GLOBALS['prefix'].$domain->$key->dom.'_'.$domain->$key->ref.'` ON `'.$GLOBALS['prefix'].'label`.`id` = `'.$GLOBALS['prefix'].$domain->$key->dom.'_'.$domain->$key->ref.'`.`id`';
					}
				}
			}

		//Si $type est null, on récupère tout les enfants
		if($noLimit) {
			if($type == null) {
				$query = 'SELECT id_son FROM '.$innerJoinL.$GLOBALS['prefix'].'_label inner join '.$GLOBALS['prefix'].'label on id = id_son '.$innerJoinR.' WHERE id_father = '.$this->id.$rightCriteria.' ORDER BY '.$this->childsOrderBy.' '.$this->childsOrder.' ;';
			}
			else {
				$query = 'SELECT id_son FROM '.$innerJoinL.$GLOBALS['prefix'].'_label inner join '.$GLOBALS['prefix'].'label on id = id_son '.$innerJoinR.' WHERE `type` = "'.$type.'" AND id_father = '.$this->id.$rightCriteria.' ORDER BY '.$this->childsOrderBy.' '.$this->childsOrder.' ;';
			}
		}
		else {
			if($type == null) {
				$query = 'SELECT id_son FROM '.$innerJoinL.$GLOBALS['prefix'].'_label inner join '.$GLOBALS['prefix'].'label on id = id_son '.$innerJoinR.' WHERE id_father = '.$this->id.$rightCriteria.' ORDER BY '.$this->childsOrderBy.' '.$this->childsOrder.' LIMIT '.($page*$this->nbChildsPerPage).','.$this->nbChildsPerPage.';';
			}
			else {
				$query = 'SELECT id_son FROM '.$innerJoinL.$GLOBALS['prefix'].'_label inner join '.$GLOBALS['prefix'].'label on id = id_son '.$innerJoinR.' WHERE `type` = "'.$type.'" AND id_father = '.$this->id.$rightCriteria.' ORDER BY '.$this->childsOrderBy.' '.$this->childsOrder.' LIMIT '.($page*$this->nbChildsPerPage).','.$this->nbChildsPerPage.';';
			}
		}

		$_rows = ZzSQL::query($query);
		$external = new ZzChildrenQuery();
		foreach($_rows as $res) {
			$newChild = ZzIO::getCleanedInstance($res['id_son']);
			$newChild->externalQuery = $external;
			$external->add($newChild);
			$_childs[] = $newChild;
		}
		
		return $_childs;
	}
	
	/**
	 * récupérer les enfant du label dans lesquels on peut écrire
	 * @return array
	 */
	public function getAllWritableChildren($type = null) {
		return $this->getWritableChildren($type,true);
	}
	/**
	 * récupérer les enfant du label dans lesquels on peut écrire
	 * @return array
	 */
	public function getWritableChildren($type = null,$noLimit = false) {
		$_childs = array(); //liste des enfants
		
		//Numéro de la page
			$page = 0;
			if(!empty($_GET['page']) > 0)
				$page = intval($_GET['page']);

		//Construction du critère de limitation des droit
			//Si statique, seul les enfants avec droit en lectures pour tous
			if($GLOBALS['isStatic'])
				$rightCriteria = ' AND otherW = 1';
			//Si dynamique 
			else {
				if(!empty($_SESSION['group']))
					foreach($_SESSION['group'] AS $key => $grp)
						if($key == 0)
							$listGroup = $grp;
						else
							$listGroup .= '|'.$grp;
				else
					$listGroup = '0';
				if(!empty($_SESSION['user']))
					$user = $_SESSION['user'];
				else
					$user = '0';
				$rightCriteria = ' AND ((OtherW=1) OR (GroupW = 1 AND `Group` REGEXP \'^'.$listGroup.'$\') OR (UserW = 1 AND User = '.$user.')';
			}

		//Si $type est null, on récupère tout les enfants
		if($noLimit) {
			if($type == null)
				$query = 'SELECT id_son FROM '.$GLOBALS['prefix'].'_label inner join '.$GLOBALS['prefix'].'label on id = id_son WHERE id_father = '.$this->id.$rightCriteria.' ORDER BY '.$this->childsOrderBy.' '.$this->childsOrder.' ;';
			else
				$query = 'SELECT id_son FROM '.$GLOBALS['prefix'].'_label inner join '.$GLOBALS['prefix'].'label on id = id_son WHERE `type` = "'.$type.'" AND id_father = '.$this->id.$rightCriteria.' ORDER BY '.$this->childsOrderBy.' '.$this->childsOrder.' ;';
		}
		else {
			if($type == null)
				$query = 'SELECT id_son FROM '.$GLOBALS['prefix'].'_label inner join '.$GLOBALS['prefix'].'label on id = id_son WHERE id_father = '.$this->id.$rightCriteria.' ORDER BY '.$this->childsOrderBy.' '.$this->childsOrder.' LIMIT '.($page*$this->nbChildsPerPage).','.$this->nbChildsPerPage.';';
			else
				$query = 'SELECT id_son FROM '.$GLOBALS['prefix'].'_label inner join '.$GLOBALS['prefix'].'label on id = id_son WHERE `type` = "'.$type.'" AND id_father = '.$this->id.$rightCriteria.' ORDER BY '.$this->childsOrderBy.' '.$this->childsOrder.' LIMIT '.($page*$this->nbChildsPerPage).','.$this->nbChildsPerPage.';';
		}
		
		$_rows = ZzSQL::query($query);
		$external = new ZzChildrenQuery();
		foreach($_rows as $res) {
			$newChild = ZzIO::getCleanedInstance($res['id_son']);
			$newChild->externalQuery = $external;
			$external->add($newChild);
			$_childs[] = $newChild;
		}
		return $_childs;
	}
	
	/**
	 * génrère la liste des pages
	 * @return string
	 */
	public function getListPage($type = null) {
		$str = ''; //liste des pages
		$nbChilds = 0; //nombre d'enfants
		$nbPages = 0; //Nombre de pages
		
		//Numéro de la page
			$page = 0;
			if(!empty($_GET['page']) > 0)
				$page = intval($_GET['page']);
				
		//Construction du critère de limitation des droit
			//Si statique, seul les enfants avec droit en lectures pour tous
			if($GLOBALS['isStatic'])
				$rightCriteria = ' AND otherR = 1';
			//Si dynamique 
			else {
				if(!empty($_SESSION['group']))
					foreach($_SESSION['group'] AS $key => $grp)
						if($key == 0)
							$listGroup = $grp;
						else
							$listGroup .= '|'.$grp;
				else
					$listGroup = '0';
				if(!empty($_SESSION['user']))
					$user = $_SESSION['user'];
				else
					$user = '0';
				$rightCriteria = ' AND ((OtherW=1) OR (GroupW = 1 AND `Group` REGEXP \'^'.$listGroup.'$\') OR (UserW = 1 AND User = '.$user.')';
			}


		//Si $type est null, on récupère tout les enfants
		if($type == null)
			$query = 'SELECT COUNT(*) as count FROM '.$GLOBALS['prefix'].'_label inner join '.$GLOBALS['prefix'].'label on id = id_son WHERE id_father = '.$this->id.$rightCriteria.';';
		else
			$query = 'SELECT COUNT(*) as count FROM '.$GLOBALS['prefix'].'_label inner join '.$GLOBALS['prefix'].'label on id = id_son WHERE `type` = "'.$type.'" AND id_father = '.$this->id.$rightCriteria.';';
		$res = ZzSQL::queryFirst($query);
		$nbChilds = $res['count'];
				
		$nbPages = $nbChilds / $this->nbChildsPerPage;
		
		for($i=0; $i<$nbPages;$i++) {
			if($i == $page)
				$str .= '
		<a href="'.ZzGetUrl::with('page',$i).'" class="selected">'.($i+1).'</a>';
			else
				$str .= '
		<a href="'.ZzGetUrl::with('page',$i).'">'.($i+1).'</a>';
		
		}
		if($nbPages>1)
			return '
	<div class="pagination">'.$this->trDom->tr('Page').':'.$str.'
	</div>';
		else
			return '
	<div class="pagination"></div>';
	}
	
	/**
	 * Défini le nombre d'enfants par page
	 * @return void
	 */
	public function setNbChildrenPerPage($nbChildsPerPage) {
		$this->nbChildsPerPage = $nbChildsPerPage;
	}
	
	/**
	 * Défini le critaire d'ordonancement des enfants
	 * @return void
	 */
	public function setChildrenOrderBy($childsOrderBy) {
		$this->childsOrderBy = $childsOrderBy;
	}
	
		/**
	 * Inverse l'ordre d'ordonancement des enfant
	 * @return void
	 */
	public function reverseChildrenOrder() {
		if($this->childsOrder == 'ASC')
			$this->childsOrder = 'DESC';
		else
			$this->childsOrder = 'ASC';
	}
	
	/**
	 * Ajoute le droit de création d'enfant pour tout le monde
	 */
	public function allowEbToCreateChildren($type) {
		$this->createChilds[$type]['user'] = 1;
		$this->createChilds[$type]['group'] = $this->domain->group->value;
		$this->createChilds[$type]['other'] = 1;
	}
	/**
	 * Retire le droit de création d'enfant pour tout le monde
	 */
	public function allowNbToCreateChildren($type) {
		$this->createChilds[$type]['user'] = 0;
		$this->createChilds[$type]['group'] = 0;
		$this->createChilds[$type]['other'] = 0;
	}
	/**
	 * Ajoute le droit de création d'enfant pour l'utilisateur
	 */
	public function allowUserToCreateChildren($type) {
		$this->createChilds[$type]['user'] = 1;
	}
	/**
	 * Ajoute le droit de création d'enfant pour le groupe
	 */
	public function allowGroupToCreateChildren($type,$group=null) {
		if($group == null)
			$group = $this->domain->group->value;
		$this->createChilds[$type]['group'] = $group;
	}
	/**
	 * Retire le droit de création d'enfant pour l'utilisateur
	 */
	public function dontAllowUserToCreateChildren($type) {
		$this->createChilds[$type]['user']= 0;
	}
	/**
	 * Retire le droit de création d'enfant pour le groupe
	 */
	public function dontAllowGroupToCreateChildren($type) {
		$this->createChilds[$type]['group'] = 0;
	}
	/**
	 * Retire le droit de création d'enfant pour les autres
	 */
	public function dontAllowOtherToCreateChildren($type) {
		$this->createChilds[$type]['group'] = 0;
	}
	/**
	 * Récupère les type d'enfants que l'on peut creer
	 */
	public function getAutoCreateChildrenPermissions() {
		if(!is_null($this->_autocreateChildsPermissions))
			return $this->_autocreateChildsPermissions;
		
		$this->_autocreateChildsPermissions = array();
		
		if($GLOBALS['isStatic']) {
			$ssreq = '( A.other = 1 )';
		}
		else {
			//En premier on transforme le tableau group en regex
				if(!empty($_SESSION['group']))
					foreach($_SESSION['group'] AS $key => $grp)
						if($key == 0)
							$listGroup = $grp;
						else
							$listGroup .= '|'.$grp;
				else
					$listGroup = '';

			//L'id de l'utilisateur
				if(!empty($_SESSION['user']))
					$user = $_SESSION['user'];
				else
					$user = '0';
			
			//Si $user = 0, alors la requête ne regarde que les le champs "other"
				if($user == 0)
					$ssreq = '( other = 1 )';
			//Si on vérifie tous le groupe et l'utilisateur
				elseif($this->domain->user->value == $user)
					$ssreq = '( other = 1 OR `group` REGEXP \'^'.$listGroup.'$\' OR user = 1 )';
				else
					$ssreq = '( other = 1 OR `group` REGEXP \'^'.$listGroup.'$\' )';
		}
		$req = 'SELECT type FROM '.$GLOBALS['prefix'].'_autocreate_childs_permissions WHERE id = ? AND '.$ssreq.' ;';

		$_res = ZzSQL::query($req,array($this->id));
		foreach($_res as $result)
				$this->_autocreateChildsPermissions[] = $result['type'];
		
		return $this->_autocreateChildsPermissions;
	}
	/**
	 * Récupère les type d'enfants que l'on peut creer
	 */
	public function getAutoCreateChildrenRules() {
		$req = 'SELECT type,user,`group`,other FROM '.$GLOBALS['prefix'].'_autocreate_childs_permissions WHERE id = ?;';
		$return = array();
		$_res = ZzSQL::query($req,array($this->id));
		foreach($_res as $result) {
			if($result['other'] == 1)
				$return[$result['type']]['all'] = true;
			$return[$result['type']]['group'] = $result['group'];
			if($result['user'] == 1)
				$return[$result['type']]['user'] = $this->domain->user->value;
			else
				$return[$result['type']]['user'] = 0;
		}
		return $return;
	}
	
	/**
	 * Ajouter un parent
	 */
	public function addParent($lid) {
		if(!array_search($lid,$this->_parentsToAdd))
			$this->_parentsToAdd[] = $lid;
	}
	/**
	 * Enlève un parent
	 */
	public function unlinkParent($lid) {
		if(!array_search($lid,$this->_parentsToUnlink))
			$this->_parentsToUnlink[] = $lid;
	}
	
	/**
	 * Supprimme le label
	 * @return	bool	true en cas de réussite, false dans le cas contraire
	 */
	public function rm() {
		
		//On verifie qu'on peux supprimer l'article
		if(empty($_SESSION['id'])) {
			if($this->domain->otherW->value = '0')
				return false;
		}
		elseif($this->domain->otherW->value = '0' and !array_search($this->domain->groupW->value,$_SESSION['group']) and $this->domain->userW->value != $_SESSION['id'])
			return false;
		
		//On verifie qu'on a pas d'enfant
			$nbChilds = 0;
			$res = ZzSQL::queryFirst('SELECT count(*) as count FROM '.$GLOBALS['prefix'].'_label WHERE id_father = ?',array($this->id));
				$nbChilds = $res['count'];
			if($nbChilds > 0)
				return false;
		
		//On récupère les parents
		$_parents = array();
		$_res = ZzSQL::query('SELECT id_father FROM '.$GLOBALS['prefix'].'_label WHERE id_son = ?',array($this->id));
		foreach($_res as $res)
			$_parents[] = $res['id_father'];
		//On supprime les liens avec les parents
			include_once $GLOBALS['cwd'].'/ZzL/manageParentsLabel.php';
			if(unlinkParents($this->id,$this->domain->type->value,$_parents,true) === false)
				return false;
		
		//On supprime le label
			;
			if(ZzSQL::exec('DELETE FROM '.$GLOBALS['prefix'].'label WHERE id = ?',array($this->id)) == 0)
				return false;
			if(ZzSQL::exec('DELETE FROM '.$this->tableName.' WHERE id = ?',array($this->id)) == 0)
				return false;

		foreach(explode('-',$_GET['label']) as $label)
			if($label != $this->id) {
				if(isSet($labelList))
					$labelList .= '-'.$label;
				else
					$labelList = $label;
			}
			if(!isSet($labelList))
				$labelList = '1';
		//echo '
		//<script language="javascript">
		//	document.location.href="index.php?label='.$labelList.'";
		//</script>';
		if($this->redirection == 'parent')
			ZzJump::toParent();
		elseif($this->redirection == 'this')
			ZzJump::toTheOtherPuZZle();
		return true;
	}
	
	
	
	/**
	 * Verifie l'integrité des données collecté, et les enregistre sur la base de données
	 * @return bool Retourne true en cas de réussite, false dans le cas contraire
	 */
	public function commit($param = 'EXECQUERY') {
		//On suppose qu'il n'y a pas d'erreur
		$error = false;
		$_values = array();
		if($this->id == null) {
			$query = 'INSERT INTO `'.$this->tableName.'` ';
			$queryKey = '';
			$queryVal = '';
		}
		else
			$query = 'UPDATE `'.$this->tableName.'` SET ';
		foreach($this->_allneeds as $key) {
			//Si ce n'est pas un champs de label
			//if(!in_array($key,array('name','dateC','dateU','user','group','type','id')))
				$item = $this->domain->$key;
			//else
			//	$item = $this->_labelDomTypes[$key];
			//Si le post n'existe pas
			if((!isSet($_POST[$key]) or $_POST[$key] == '') and $item->nullable == false) {
				$error = true;
				$GLOBALS['errors'][$key] = $this->tr->tr('notNull');
			}
			//Si valeur refusé
				//Par le domType
				if(!$item->setValue($_POST[$key])) {
					$error = true;
				}
				//Par la domaine
				if(method_exists($this->domainName,'check'.$key) and !$this->domain->{'check'.$key}())
					$error = true;
			if(!in_array($key,array('name','dateC','dateU','user','group','type','id')))
				$_values[$key] = addslashes($item->value);
			
		}

		//Si pas d'erreur on enregistre
		if($error) {
			return false;
		}
		if($param == 'EXECQUERY') {
			
			//Execution de toute les requêtes onCommit()
			foreach($this->_allneeds as $need) {
				$this->domain->$key->onCommit($this);
			}
			foreach($this->_allneeds as $need) {
				$this->domain->onCommit($this);
			}
			
			include_once $GLOBALS['cwd'].'/ZzL/manageLabel.php';
			$first = true;
			foreach($_values as $key => $val) {
				//On execute les méthodes onValidation

				
				if($this->domain->$key->quoted)
					$value = "'$val'";
				else
					$value = $val;
				if($this->id == null) {
					if(!$first) {
						$queryKey .= ', `'.$key.'`';
						$queryVal .= ', '.$value;
					}
					else {
						$queryKey .= '`'.$key.'`';
						$queryVal .= $value;
					}
				}
				else {
					if(!$first) {
						$query .= ', ';
					}
					$query .= '`'.$key.'` = '.$value;
				}
				$first = false;
			}
			if($this->id == null) {
				$getId = ZzCreateLabel($this->domain->name->value,$this->domain->type->value,$this->domain->dateC->value,$this->domain->user->value,$this->domain->group->value,$this->domain->userR->value.','.$this->domain->userW->value.','.$this->domain->groupR->value.','.$this->domain->groupW->value.','.$this->domain->otherR->value.','.$this->domain->otherW->value,array($this->domain->parentLabel->value));
				if($getId === false)
					$error = true;
				else
					$_SESSION['tmpId'.$GLOBALS['tmpId']] = $getId;
				$query = $query.' (`id`, '.$queryKey.') VALUES('.$getId.' ,'.$queryVal.')';
			}
			else {
				if(!ZzUpdateLabel($this->id,$this->domain->name->value,$this->domain->dateC->value,$this->domain->parentLabel->value))
					$error = true;
				$query .= ' WHERE id=?';
				$getId = $this->id;
			}

		if($error === true)
			return false;

		if(count($_values) != 0)
			ZzSQL::exec($query,array($this->id));
		
		require_once $GLOBALS['cwd'].'/ZzL/setAutoCreateChildsPermissions.php';
		foreach($this->createChilds as $type => $val) 
			setAutoCreateChildsPermissions($getId,$type,@$val['user'],@$val['group'],@$val['other']);
		
		if(!empty($this->_parentsToAdd) or !empty($this->_parentsToUnlink)) {
			include_once $GLOBALS['cwd'].'/ZzL/manageParentsLabel.php';
			if(!empty($this->_parentsToAdd))
				addParents($getId,$this->domain->type->value,$this->_parentsToAdd);
			if(!empty($this->_parentsToUnlink))
				unlinkParents($getId,$this->domain->type->value,$this->_parentsToUnlink);
			
		}
		
		$this->id = $getId;
		$labelList = $getId;
		foreach(explode('-',$_GET['label']) as $label)
			if(is_numeric($label) and $label != $getId)
				$labelList .= '-'.$label;
// 		echo '
// 		<script language="javascript">
// 			document.location.href="index.php?label='.$labelList.'";
// 		</script>';
//echo $query;
			//Execution de toute les requêtes afterCommit()
			foreach($this->_allneeds as $need) {
				$this->domain->$key->afterCommit($this);
			}
			foreach($this->_allneeds as $need) {
				$this->domain->afterCommit($this);
			}

		if($this->redirection == 'parent')
			ZzJump::toparent();
		elseif($this->redirection == 'this')
			ZzJump::toTheOtherPuZZle($this->id);
		}
		return true;
	}
	
	/**
	 * Informe si un enregistrement est possible
	 * @return bool Retourn false si l'enregistrement est possible, true dans le cas contraire
	 */
	public function isNotCommitable() {
		if(empty($_POST['IOForm'.$this->id]))
			return false;
		else
			return !$this->commit('DONTEXECQUERY'); 
	}
	/**
	 * Effectue les enregistrements éventuels
	 */
	public function __destruct() {
		if(!empty($_POST['IOForm'.$this->id]))
			$this->commit();
	}
}
?>